package org.tangolyricstagger;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.jaudiotagger.audio.AudioFileFilter;
import org.tangolyricstagger.gui.Settings;
import org.tangolyricstagger.model.TagInfo;
import org.tangolyricstagger.model.TagScanResults;

@Slf4j
public class FindTangoFiles {

    TagReader tagReader = new TagReader();

    public TagScanResults find(Settings settings) throws FileNotFoundException {
        TagScanResults results = new TagScanResults();
        File rootDirectory = new File(settings.getDirectory());
        String genresString = settings.getGenres();
        String[] genres = StringUtils.split(genresString, ',');
        for (int i = 0; i < genres.length; i++) {
            genres[i] = StringUtils.strip(genres[i]);
        }
        validateDirectory(rootDirectory);
        List<File> files = getFileListing(rootDirectory);

        // print out all file names, in the the order of File.compareTo()

        log.info("Start reading tags in files, rootDirectory=" + rootDirectory.getAbsolutePath());
        int i = 0;
        for (File file : files) {
            // System.out.println("Create tag for " + file);

            TagInfo tagInfo;
            try {
                tagInfo = tagReader.createTagInfo(file);
            } catch (Exception e) {
                System.err.println(e.getMessage());
                continue;
            }
            boolean considerGenre = false;
            String genre = tagInfo.getGenre();
            for (String consideredGenre : genres) {
                if (StringUtils.contains(genre, consideredGenre)) {
                    considerGenre = true;
                    break;
                }
            }
            if (considerGenre) {
                results.addTagInfo(tagInfo);
            } else {
                results.addIgnoredGenre(genre);
                log.info("Ignored genre: " + genre + " - considering only " + ArrayUtils.toString(genres));
            }
            if ((++i % 100) == 0) {
                log.info(i + " files analyzed");
            }
        }

        results.sortTagInfos();
        return results;
    }

    static private List<File> getFileListing(File aStartingDir) throws FileNotFoundException {
        List<File> result = new ArrayList<File>();
        File[] filesAndDirs = aStartingDir.listFiles(new AudioFileFilter(true));
        List<File> filesDirs = Arrays.asList(filesAndDirs);
        for (File file : filesDirs) {
            if (!file.isFile()) {
                // must be a directory
                // recursive call!
                List<File> deeperList = getFileListing(file);
                result.addAll(deeperList);
            } else {
                result.add(file);
            }
        }
        return result;
    }

    /**
     * Directory is valid if it exists, does not represent a file, and can be read.
     */
    static private void validateDirectory(File aDirectory) throws FileNotFoundException {
        if (aDirectory == null) {
            throw new IllegalArgumentException("Directory should not be null.");
        }
        if (!aDirectory.exists()) {
            throw new FileNotFoundException("Directory does not exist: " + aDirectory);
        }
        if (!aDirectory.isDirectory()) {
            throw new IllegalArgumentException("Is not a directory: " + aDirectory);
        }
        if (!aDirectory.canRead()) {
            throw new IllegalArgumentException("Directory cannot be read: " + aDirectory);
        }
    }
}
